/*******************************************************************************
 * FilePath    : /ble_app_peripheral_uart_simple/Src/BSP/BSP.c
 * Version     : 1.0
 * Brief       :
 * Author      : AndrewHu
 * Company     : Shanghai MacroGiga Electronics CO.,Ltd
 * Email       : Hubinbo@macrogiga.com
 * Date        : 2020-04-03 15:06:14
 * LastEditors : AndrewHu
 * LastEditTime: 2022-07-14 14:52:39
 * Description :
 ******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <Includes.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define EnterSleepDelay_set 0xf0
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static u8 RunningMode = RunningMode_Normal;   //设置运行模式
static u8 RunningStatus = RunningMode_Normal; //当前运行状态
static u8 EnterSleepDelay = 0x00;
/* Private function ----------------------------------------------------------*/
/* extern --------------------------------------------------------------------*/
/*******************************************************************************
 * Function    : ClearEnterSleepDelay
 * Brief       : 延时进入休眠
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-17 13:28:22
 * Description :
 ******************************************************************************/
void ClearEnterSleepDelay(void)
{
    EnterSleepDelay = 0x00;
}
/*******************************************************************************
 * Function    : GetRunningMode
 * Brief       : 获取当前运行模式
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-06 00:41:31
 * Description :
 ******************************************************************************/
u8 GetRunningMode(void)
{
    return RunningMode;
}
/*******************************************************************************
 * Function    : GetRunningStatus
 * Brief       : 获取当前运行状态
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-17 13:37:49
 * Description :
 ******************************************************************************/
u8 GetRunningStatus(void)
{
    return RunningStatus;
}
/*******************************************************************************
 * Function    : SetRunningMode
 * Brief       : 设定运行模式
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-17 13:37:51
 * Description :
 ******************************************************************************/
void SetRunningMode(u8 mode)
{
    RunningMode = mode;
}
/*******************************************************************************
 * Function    : SetRunningStatus
 * Brief       :
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-23 15:53:09
 * Description :
 ******************************************************************************/
void SetRunningStatus(u8 status)
{
    RunningStatus = status;
}
/*******************************************************************************
 * Function    : User_SystemClock_Config
 * Brief       : 系统时钟初始化函数，初始化之前先复位所有时钟
 * Parameter   : {u8} freq
 * Returns     :
 * Date        : 2020-04-03 15:29:16
 * Description :
 ******************************************************************************/
void User_SystemClock_Config(u8 freq)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    static u8 SystemClock = 0;

    if (SystemClock == freq)
        return; //当前时钟没变

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HIRC;
    RCC_OscInitStruct.HIRCState = RCC_HIRC_ON;

    switch (freq)
    {
    case SystemClock_8M:
        RCC_OscInitStruct.HIRCCalibrationValue = RCC_HIRCCALIBRATION_8M;
        break;
    case SystemClock_16M:
        RCC_OscInitStruct.HIRCCalibrationValue = RCC_HIRCCALIBRATION_16M;
        break;
    case SystemClock_22M:
        RCC_OscInitStruct.HIRCCalibrationValue = RCC_HIRCCALIBRATION_22M;
        break;
    case SystemClock_24M:
        RCC_OscInitStruct.HIRCCalibrationValue = RCC_HIRCCALIBRATION_24M;
        break;
    default:
        freq = SystemClock_4M;
        RCC_OscInitStruct.HIRCCalibrationValue = RCC_HIRCCALIBRATION_4M;
        break;
    }
    SystemClock = freq; //标记当前系统时钟

    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    /**Initializes the CPU, AHB and APB busses clocks
     */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HIRC;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APBCLKDivider = RCC_PCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct) != HAL_OK)
    {
        Error_Handler();
    }
}
/*******************************************************************************
 * Function    : Led_Init
 * Brief       : 灯初始化
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 16:01:38
 * Description :
 ******************************************************************************/
static void Led_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitStructure.Pin = LED_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT;
    GPIO_InitStructure.OpenDrain = GPIO_PUSHPULL;
    GPIO_InitStructure.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
    GPIO_InitStructure.SlewRate = GPIO_SLEW_RATE_LOW;
    GPIO_InitStructure.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
    GPIO_InitStructure.Pull = GPIO_NOPULL; // GPIO_NOPULL;
    HAL_GPIO_Init(LED_GPIO, &GPIO_InitStructure);
    HAL_GPIO_WritePin(LED_GPIO, LED_PIN, GPIO_PIN_SET); // high, off
}
/*******************************************************************************
 * Function    : Key_Init
 * Brief       : 按键IO初始化
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 16:29:58
 * Description :
 ******************************************************************************/
static void Key_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    __HAL_RCC_GPIOC_CLK_ENABLE();

    GPIO_InitStructure.Pin = KEY_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    GPIO_InitStructure.OpenDrain = GPIO_PUSHPULL;
    GPIO_InitStructure.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
    GPIO_InitStructure.SlewRate = GPIO_SLEW_RATE_LOW;
    GPIO_InitStructure.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
    GPIO_InitStructure.Pull = GPIO_PULLDOWN; // GPIO_NOPULL;
    HAL_GPIO_Init(KEY_GPIO, &GPIO_InitStructure);
}
/*******************************************************************************
 * Function    : Uart_Init
 * Brief       :
 * Parameter   : {u32} baudRate-波特率
 * Returns     :
 * Date        : 2020-04-03 16:53:11
 * Description :
 ******************************************************************************/
static void Uart_Init(u32 baudRate)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    UART_HandleTypeDef UartxHandle;

    __HAL_RCC_GPIOB_CLK_ENABLE();

    GPIO_InitStructure.OpenDrain = GPIO_PUSHPULL;
    GPIO_InitStructure.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
    GPIO_InitStructure.SlewRate = GPIO_SLEW_RATE_HIGH;
    GPIO_InitStructure.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
    GPIO_InitStructure.Pull = GPIO_PULLUP; //上拉

    // PB5-RX,PB4-TX
    GPIO_InitStructure.Pin = UART_RX_PIN; // RX
    GPIO_InitStructure.Mode = GPIO_MODE_AF;
    GPIO_InitStructure.Alternate = GPIO_AF5_UART0_RXD;
    HAL_GPIO_Init(UART_RX_GPIO, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = UART_TX_PIN; // TX
    GPIO_InitStructure.Mode = GPIO_MODE_AF;
    GPIO_InitStructure.Alternate = GPIO_AF5_UART0_TXD;
    HAL_GPIO_Init(UART_TX_GPIO, &GPIO_InitStructure);

    __HAL_RCC_UART0_CLK_ENABLE();

    UartxHandle.Instance = UART0;
    UartxHandle.Init.BaudRate = baudRate;
    UartxHandle.Init.BaudDouble = UART_BAUDDOUBLE_ENABLE;
    UartxHandle.Init.WordLength = UART_WORDLENGTH_8B;
    UartxHandle.Init.Parity = UART_PARITY_NONE;
    UartxHandle.Init.Mode = UART_MODE_TX_RX;
    HAL_UART_Init(&UartxHandle);

    // HAL_UART_Transmit_IT(&sUartxHandle, ucSendData, sizeof(ucSendData));
    // HAL_UART_Receive_IT(&sUartxHandle, ucReceiveData, sizeof(ucReceiveData));
    UART0->SCON |= UART_INTSR_RI | UART_INTSR_TI;
    HAL_NVIC_EnableIRQ(UART_IRQ);
}
/*******************************************************************************
 * Function    : IRQ_Init
 * Brief       : 蓝牙中断设置
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 16:59:42
 * Description :
 ******************************************************************************/
static void IRQ_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    __HAL_RCC_GPIOB_CLK_ENABLE();

    //蓝牙中断
    GPIO_InitStructure.Pin = IRQ_PIN;
    GPIO_InitStructure.Pull = GPIO_PULLUP;
    GPIO_InitStructure.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
    GPIO_InitStructure.SlewRate = GPIO_SLEW_RATE_HIGH;
    GPIO_InitStructure.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
    /* Configure Button pin as input */
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    HAL_GPIO_Init(IRQ_GPIO, &GPIO_InitStructure);

    /* Configure Button pin as input with External interrupt */
    GPIO_InitStructure.Mode = EXTI_MODE;
    GPIO_InitStructure.Exti.Enable = GPIO_EXTI_INT_ENABLE;
    GPIO_InitStructure.Exti.EdgeLevelSel = GPIO_EXTI_INT_EDGE;
    GPIO_InitStructure.Exti.RiseFallSel = GPIO_EXTI_INT_LOWFALL;
    HAL_GPIO_Init(IRQ_GPIO, &GPIO_InitStructure);

    __HAL_GPIO_EXTI_CLEAR_FLAG(IRQ_GPIO, IRQ_PIN);
    /* Enable and set Button EXTI Interrupt to the lowest priority */
    HAL_NVIC_SetPriority(IRQ_IRQ, PRIORITY_HIGH);
    HAL_NVIC_EnableIRQ(IRQ_IRQ);
}
/*******************************************************************************
 * Function    : GPIO_Init
 * Brief       : 所有IO初始化
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-16 18:38:14
 * Description :
 ******************************************************************************/
static void GPIO_Init(void)
{
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();

    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_4 | GPIO_PIN_5);
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
    HAL_GPIO_DeInit(GPIOD, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6);
}
/*******************************************************************************
 * Function    : BSP_Init
 * Brief       : 硬件（IO）初始化
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 15:56:40
 * Description :
 ******************************************************************************/
void BSP_Init(void)
{
    HAL_Init();                               //滴答时钟1ms计时
    User_SystemClock_Config(SystemClock_24M); //系统时钟设定
    GPIO_Init();                              // IO设置
    Led_Init();                               //指示灯
    Key_Init();                               //按键
    Uart_Init(GetBaudRate());                 //串口设置
    SPIM_Init();                              //蓝牙通讯IO初始化
    IRQ_Init();                               //蓝牙Irq中断设置
    WDG_Init();                               //看门狗使能
}
/*******************************************************************************
 * Function    : setLedPinStatus
 * Brief       : LED亮灭控制
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 15:59:24
 * Description :
 ******************************************************************************/
void setLedPinStatus(u8 status)
{
    if (status)
        HAL_GPIO_WritePin(LED_GPIO, LED_PIN, GPIO_PIN_RESET); // low, on
    else
        HAL_GPIO_WritePin(LED_GPIO, LED_PIN, GPIO_PIN_SET); // high, off
}
/*******************************************************************************
 * Function    : getLedPinStatus
 * Brief       : 获取LED灯亮灭状态
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-04 15:20:46
 * Description :
 ******************************************************************************/
u8 getLedPinStatus(void)
{
    if (HAL_GPIO_ReadPin(LED_GPIO, LED_PIN))
        return 0; // high, off
    else
        return 1;
}
/*******************************************************************************
 * Function    : Key_Interrupt_Status
 * Brief       : 按键唤醒功能
 * Parameter   : 0-disable，1-enable
 * Returns     :
 * Date        : 2020-04-17 17:32:25
 * Description :
 ******************************************************************************/
static void Key_Interrupt_Status(u8 status)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    HAL_GPIO_DeInit(KEY_GPIO, KEY_PIN);
    HAL_NVIC_DisableIRQ(KEY_IRQ);

    GPIO_InitStructure.Pin = KEY_PIN;
    GPIO_InitStructure.OpenDrain = GPIO_PUSHPULL;
    GPIO_InitStructure.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
    GPIO_InitStructure.SlewRate = GPIO_SLEW_RATE_LOW;
    GPIO_InitStructure.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
    GPIO_InitStructure.Pull = GPIO_PULLDOWN; // GPIO_NOPULL;

    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    HAL_GPIO_Init(KEY_GPIO, &GPIO_InitStructure);

    if (status)
    { //使能中断
        GPIO_InitStructure.Mode = EXTI_MODE;
        GPIO_InitStructure.Exti.Enable = GPIO_EXTI_INT_ENABLE;
        GPIO_InitStructure.Exti.EdgeLevelSel = GPIO_EXTI_INT_EDGE;
        GPIO_InitStructure.Exti.RiseFallSel = GPIO_EXTI_INT_HIGHRISE; //上升沿中断
        HAL_GPIO_Init(KEY_GPIO, &GPIO_InitStructure);

        __HAL_GPIO_EXTI_CLEAR_FLAG(KEY_GPIO, KEY_PIN);

        HAL_NVIC_SetPriority(KEY_IRQ, PRIORITY_LOW);
        HAL_NVIC_EnableIRQ(KEY_IRQ);
    }
}
/*******************************************************************************
 * Function    : getKeyPinStatus
 * Brief       : 获取按键引脚状态
 * Parameter   : 0-up,1-down
 * Returns     :
 * Date        : 2021-05-08 17:53:55
 * Description :
 ******************************************************************************/
u8 getKeyPinStatus(void)
{
    if (HAL_GPIO_ReadPin(KEY_GPIO, KEY_PIN))
        return 1; //按下
    else
        return 0; //松开
}
/*******************************************************************************
 * Function    : ChangeBaudRate
 * Brief       : 更改波特率
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 16:52:30
 * Description :
 ******************************************************************************/
void ChangeBaudRate(u32 bRate)
{
    SetBaudRate(bRate);
    Uart_Init(bRate); //初始化串口1
}
/*******************************************************************************
 * Function    : Uart_Interrupt_Status
 * Brief       : 设置串口RXD引脚中断状态
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-05 23:39:50
 * Description : 当芯片进入休眠时，用RX唤醒芯片；芯片通过RX唤醒后，切换为串口通讯脚
 ******************************************************************************/
static void Uart_Interrupt_Status(u8 status)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    ClearEnterSleepDelay(); //刚唤醒，进入休眠延时重新计时
    HAL_GPIO_DeInit(GPIOD, GPIO_PIN_3);

    // UART0_RX
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    GPIO_InitStructure.OpenDrain = GPIO_PUSHPULL;
    GPIO_InitStructure.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
    GPIO_InitStructure.SlewRate = GPIO_SLEW_RATE_HIGH;
    GPIO_InitStructure.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
    GPIO_InitStructure.Pull = GPIO_PULLUP;
    GPIO_InitStructure.Alternate = 0x00; //不复用
    GPIO_InitStructure.Pin = GPIO_PIN_3;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);

    /* Configure Button pin as input with External interrupt */
    GPIO_InitStructure.Mode = EXTI_MODE;
    GPIO_InitStructure.Exti.EdgeLevelSel = GPIO_EXTI_INT_EDGE;
    GPIO_InitStructure.Exti.RiseFallSel = GPIO_EXTI_INT_LOWFALL;
    if (status)
    { //使能IO中断
        GPIO_InitStructure.Exti.Enable = GPIO_EXTI_INT_ENABLE;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);

        /* Enable and set Button EXTI Interrupt to the lowest priority */
        HAL_NVIC_SetPriority(GPIOD_IRQn, PRIORITY_LOW);
        HAL_NVIC_EnableIRQ(GPIOD_IRQn);
    }
    else
    { //关闭IO中断
        GPIO_InitStructure.Exti.Enable = GPIO_EXTI_INT_DISABLE;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);

        GPIO_InitStructure.Mode = GPIO_MODE_AF;
        GPIO_InitStructure.Alternate = GPIO_AF5_UART0_RXD;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
    }
    __HAL_GPIO_EXTI_CLEAR_FLAG(GPIOD, GPIO_PIN_3);
}
/*******************************************************************************
 * Function    : Mcu_Sleep_Status
 * Brief       : 芯片MCU部分进入低功耗
 * Parameter   : 0x00-sleep,0x01-BLE唤醒，0x02-按键唤醒，0x03-串口唤醒
 * Returns     :
 * Date        : 2020-04-17 13:52:12
 * Description :
 ******************************************************************************/
void Mcu_Sleep_Status(u8 status)
{
    static u8 SleepStatus = 0x00; //默认非低功耗模式

    User_SystemClock_Config(SystemClock_24M); //主频切换为24M

    switch (status)
    {
    case 0x01: // BLE唤醒
    {
    }
    break;
    case 0x02: //按键唤醒
    {
        if (SleepStatus != 0)
        { //当前为休眠状态
            SleepStatus = 0x00;
            Uart_Interrupt_Status(0); //按键退出低功耗
            Key_Interrupt_Status(0);  //串口退出低功耗
            ClearEnterSleepDelay();   //进入低功耗延时
            RunningMode = RunningMode_Normal;
            Printf_Wakeup(); // test
        }
    }
    break;
    case 0x03: //串口唤醒
    {
        if (SleepStatus != 0)
        { //当前为休眠状态
            SleepStatus = 0x00;
            Uart_Interrupt_Status(0); //按键退出低功耗
            Key_Interrupt_Status(0);  //串口退出低功耗
            ClearEnterSleepDelay();   //进入低功耗延时
            RunningMode = RunningMode_Normal;
            Printf_Wakeup(); // test
        }
    }
    break;
    default: //休眠
    {
        if (SleepStatus != 1) //设置中断,防止重复设置
        {
            Uart_Interrupt_Status(1); //串口唤醒使能
            Key_Interrupt_Status(1);  //按键进入休眠
            SleepStatus = 0x01;       //完成低功耗设置
        }
        User_SystemClock_Config(SystemClock_4M); //主频切换为4M
        //休眠指令
        SCB->SCR |= 0x4;
        __WFI();
    }
    break;
    }
}
/*******************************************************************************
 * Function    : Radio_Standby_Status
 * Brief       : 蓝牙射频端工作状态
 * Parameter   : 0-running,1-standby
 * Returns     :
 * Date        : 2020-04-17 13:56:49
 * Description :
 ******************************************************************************/
static void Radio_Standby_Status(u8 status)
{
    static u8 RadioStandbyStatus = 0x00;

    if (RadioStandbyStatus)
    { //目前处于休眠状态
        if (status == 0)
            radio_resume(); //唤醒蓝牙
    }
    else
    { //目前处于工作状态
        if (status)
            radio_standby(); //关闭蓝牙功能
    }
    RadioStandbyStatus = status; //保存工作状态
}
/*******************************************************************************
 * Function    : IrqMcuGotoSleepAndWakeup
 * Brief       : 运行模式检查及判断
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 15:58:39
 * Description :
 ******************************************************************************/
void IrqMcuGotoSleepAndWakeup(void) // auto goto sleep AND wakeup, porting api
{
    if (Get_SWDG_Time() >= 6)
    {
        WDG_ReloadCounter();
        //重新激活蓝牙
        HAL_NVIC_DisableIRQ(GPIOB_IRQn);
        Ble_Init();
        __HAL_GPIO_EXTI_CLEAR_FLAG(GPIOB, GPIO_PIN_4);
        HAL_NVIC_EnableIRQ(GPIOB_IRQn);
        ble_run_interrupt_start(160 * 2); //广播间隔设定，320*0.625=200 ms
        // test
        //  Uart_Send_String((u8 *)"IND:radio rest!\r\n", 16);
        return;
    }

    if ((RunningStatus != RunningMode_Stop) && (RunningStatus != RunningMode_Standby))
    {
        //蓝牙射频没有关闭，需要判断是否可以进入休眠接口
        if (ble_run_interrupt_McuCanSleep() == 0)
        {
            //蓝牙不能进入休眠，EnterSleepDelay清零
            ClearEnterSleepDelay();
            return;
        }
    }

    //进入低功耗延时，当EnterSleepDelay清零时开始累计次数
    if ((GetUartStatus() != 0) || (GetKeyStatus() != 0))
    {
        //串口有数据待处理或按键按下，不能进入休眠
        ClearEnterSleepDelay();
        return;
    }
    else if (EnterSleepDelay < EnterSleepDelay_set)
    {
        EnterSleepDelay++;
        return;
    }
    //可以进入休眠，休眠模式判断
    switch (RunningMode)
    {
    case RunningMode_Normal:
        /* Normal ------------------------------------------------------------*/
        RunningStatus = RunningMode_Normal;
        Radio_Standby_Status(0); //射频工作
        break;
    case RunningMode_Sleep:
        /* Sleep -------------------------------------------------------------*/
        RunningStatus = RunningMode_Sleep;
        Radio_Standby_Status(0); //蓝牙射频工作
        Mcu_Sleep_Status(0);     // MCU部分进入休眠
        break;
    case RunningMode_Stop:
        /* Stop --------------------------------------------------------------*/
        //省电，蓝牙停止，仅MCU运行，(功耗比sleep大)
        if (GetConnectedStatus())
        {
            ble_disconnect(); //连接状态，先断开蓝牙
        }
        else
        {
            RunningStatus = RunningMode_Stop;
            Radio_Standby_Status(1); //蓝牙射频不工作
            //设定看门狗唤醒和串口唤醒功能
            WDG_ReloadCounter();
        }
        break;
    case RunningMode_Standby:
        /* Standby -----------------------------------------------------------*/
        //整个系统进入休眠(功耗最低)
        if (GetConnectedStatus())
        {
            ble_disconnect(); //连接状态，先断开蓝牙
        }
        else
        {
            RunningStatus = RunningMode_Standby;
            Radio_Standby_Status(1); //蓝牙射频不工作
            setLedPinStatus(0);      //关闭指示灯
            Mcu_Sleep_Status(0);     // MCU部分进入休眠
        }
        break;
    default:
        /* Else --------------------------------------------------------------*/
        //默认省电模式
        RunningMode = RunningMode_Sleep;
        RunningStatus = RunningMode_Sleep;
        Radio_Standby_Status(0); //蓝牙射频工作
        break;
    }
}
/*******************************************************************************
0~3KB BootCode
3~4KB UserData
4~34KB RunCode
34~64KB OTA
*******************************************************************************/
#define FLASH_E2PROM_ADDR_BASE (0x00000000)
//#define FLASH_BOOT_ROM_SIZE    (3*1024)
//#define FLASH_E2PROM_ADDR_USR  (FLASH_E2PROM_ADDR_BASE + FLASH_BOOT_ROM_SIZE)
#define FLASH_E2PROM_ADDR_OTA (FLASH_E2PROM_ADDR_BASE + 34 * 1024)

#define APPLICATION_ADDRESS (uint32_t)0x00001010
/*******************************************************************************
 * Function    : OtaSystemReboot
 * Brief       :
 * Parameter   :
 * Returns     :
 * Date        : 2020-03-23 15:03:36
 * Description : OTA完成后系统重启
 ******************************************************************************/
void OtaSystemReboot(void) // porting api
{
    NVIC_SystemReset();
}
/*******************************************************************************
 * Function    : GetOtaAddr
 * Brief       :
 * Parameter   :
 * Returns     :
 * Date        : 2020-03-23 15:03:54
 * Description : 获取OTA的起始地址
 ******************************************************************************/
u32 GetOtaAddr(void)
{
    return FLASH_E2PROM_ADDR_OTA;
}
/*******************************************************************************
 * Function    : WriteFlashE2PROM
 * Brief       :
 * Parameter   :
 * Returns     :
 * Date        : 2020-03-23 15:03:50
 * Description : OTA时擦写Flash
 ******************************************************************************/
void WriteFlashE2PROM(u8 *data, u16 len, u32 pos, u8 flag) // 4 bytes aligned
{
    u32 t;

    while (len >= 4)
    {
        t = data[3];
        t <<= 8;
        t |= data[2];
        t <<= 8;
        t |= data[1];
        t <<= 8;
        t |= data[0];
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, pos, t);
        pos += 4;
        len -= 4;
        data += 4;
    }
}
/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */

    /* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/*******************************************************************************
 * Function    :
 * Brief       :
 * Parameter   :
 * Returns     :
 * Date        : 2020-04-03 15:58:17
 * Description : DO NOT REMOVE, used in ble lib
 ******************************************************************************/
void McuGotoSleepAndWakeup(void)
{
}
void SysClk8to48(void)
{
}
void SysClk48to8(void)
{
}
void DisableEnvINT(void)
{
}
void EnableEnvINT(void)
{
}
void UpdateLEDValueAll(void)
{
}
unsigned char aes_encrypt_HW(unsigned char *_data, unsigned char *_key)
{
    // RCC->UNLOCK = 0x55AA6699;
    // RCC->SWDIOCR = (0x5A69 << RCC_SWDIOCR_KEY_Pos); //关闭SWD
    // RCC->UNLOCK = 0x55AA6698;

    // RCC->UNLOCK = 0x55AA6699;
    // RCC->SWDIOCR = ((0x5A69 << RCC_SWDIOCR_KEY_Pos) | 0x01); //打开SWD
    // RCC->UNLOCK = 0x55AA6698;
    return 0;
}
